/**
 * @file boards\gd32f303cx\bsp\bsp_key.c
 *
 * bsp_key.c is not free software: you can not redistribute it and/or modify
 * it before obtaining permission from moorgen.
 *
 * This program is distributed in the hope that it will be useful
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the license along with this program
 * from moorgen. If not, please contact us.
 *
 * @author HinsShum hinsshum@qq.com
 *
 * @encoding utf-8
 */

/*---------- includes ----------*/
#include "bsp_key.h"
#include "gd32f30x_libopt.h"
#include "gpio_group.h"
#include "options.h"


/*---------- macro ----------*/
#define x_rcu0 RCU_GPIOA
#define x_port0 GPIOA
#define x1_pin1 GPIO_PIN_3
#define x1_pin3 GPIO_PIN_7
#define x1_pin4 GPIO_PIN_5
#define x2_pin1 GPIO_PIN_0
#define x3_pin1 GPIO_PIN_2
#define x3_pinse2 GPIO_PIN_4
#define x4_pin1 GPIO_PIN_1

#define x_rcu1 RCU_GPIOB
#define x_port1 GPIOB
#define x1_pinse1 GPIO_PIN_0
#define x2_pin2 GPIO_PIN_15
#define x2_pin3 GPIO_PIN_14
#define x2_pin4 GPIO_PIN_13
#define x2_pinse2 GPIO_PIN_12
#define x4_pinse1 GPIO_PIN_9
#define x4_pinse2 GPIO_PIN_8

#define x_rcu2 RCU_GPIOC
#define x_port2 GPIOC
#define x1_pin2 GPIO_PIN_4
#define x1_pinse2 GPIO_PIN_5
#define x2_pinse1 GPIO_PIN_7
#define x3_pin2 GPIO_PIN_0
#define x3_pin3 GPIO_PIN_1
#define x3_pin4 GPIO_PIN_2
#define x3_pinse1 GPIO_PIN_3
#define x4_pin2 GPIO_PIN_13
#define x4_pin3 GPIO_PIN_14
#define x4_pin4 GPIO_PIN_15
#define ADC0_NUMBER 10
/*---------- type define ----------*/
typedef enum {
    x1_pin_id1 = 1,
    x1_pin_id2,
    x1_pin_id3,
    x1_pin_id4,
    x2_pin_id1,
    x2_pin_id2,
    x2_pin_id3,
    x2_pin_id4,
    x3_pin_id1,
    x3_pin_id2,
    x3_pin_id3,
    x3_pin_id4,
    x4_pin_id1,
    x4_pin_id2,
    x4_pin_id3,
    x4_pin_id4,
    x_pin_id_null = 0xff,
} x_pin_id;
typedef enum {
    type_null = 0xF1,
    type_1_4,
    type_1_2_y,
    type_1_2_x,
    type_1_2_slide,
    type_1_2_sw,
} all_type;
typedef struct {
    all_type part1;
    all_type part2;
    all_type part3;
    all_type part4;
} board_all_type;
/*---------- variable prototype ----------*/
/*---------- function prototype ----------*/
static bool bsp_init(void);
static void bsp_deinit(void);
static void bsp_check_part(bool is_init);
static unsigned char bsp_get(unsigned char num);
uint16_t adc_slide_buff[ADC0_NUMBER];

board_all_type board_all_part;
/*---------- variable ----------*/
static gpio_group_describe_t key = {
    .group_name = "key",
    .ops.init = bsp_init,
    .ops.deinit = bsp_deinit,
    .ops.get = bsp_get,
    .ops.set = NULL,
    .ops.user_function = bsp_check_part,
    .user_date_special = adc_slide_buff,
};
DEVICE_DEFINED(key, gpio_group, &key);

/*---------- function ----------*/
static void check_slide_init_adc_dma(board_all_type temp) {
    rcu_periph_clock_enable(RCU_ADC0);
    rcu_periph_clock_enable(RCU_DMA0);

    rcu_adc_clock_config(RCU_CKADC_CKAHB_DIV6);
    dma_parameter_struct dma_data_parameter;

    /* deinitialize DMA channel */
    dma_deinit(DMA0, DMA_CH0);
    /* initialize DMA0 channel0(ADC0) */
    dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_data_parameter.memory_addr = (uint32_t)(&adc_slide_buff);
    dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT;
    dma_data_parameter.number = (uint32_t)ADC0_NUMBER;
    dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));
    dma_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
    dma_data_parameter.priority = DMA_PRIORITY_HIGH;
    dma_init(DMA0, DMA_CH0, &dma_data_parameter);
    /* enable DMA channel */
    dma_circulation_enable(DMA0, DMA_CH0);

    dma_channel_enable(DMA0, DMA_CH0);
    /* reset ADC */
    adc_deinit(ADC0);
    /* ADC scan mode function enable */
    adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);
    /* ADC trigger config */
    adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL,
        ADC0_1_2_EXTTRIG_REGULAR_NONE);
/* ADC data alignment config */
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
    /* configure the ADC sync mode */
    adc_mode_config(ADC_MODE_FREE);
    /* ADC channel length config */
    adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1);

    /* ADC regular channel config */
    if (temp.part2 == board_all_part.part2 && temp.part2 != 0) {
        gpio_init(x_port0, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, x2_pin1);
        adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_0,
            ADC_SAMPLETIME_239POINT5);
    }
    else if (temp.part1 == board_all_part.part1 && temp.part1 != 0) {
        gpio_init(x_port0, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, x1_pin1);
        adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_3,
            ADC_SAMPLETIME_239POINT5);
    }
    /* ADC external trigger enable */
    adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);
    /* ADC resolution config */
    adc_resolution_config(ADC0, ADC_RESOLUTION_12B);
    /* enable ADC interface */
    adc_enable(ADC0);
    __delay_ms(10);
    /* ADC calibration and reset calibration */
    adc_calibration_enable(ADC0);
    /* ADC DMA function enable */
    adc_dma_mode_enable(ADC0);
    /* trigger start ADCx_channels conversion */
    adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
}
void bsp_check_part(bool is_init) {
    volatile unsigned char get_key_max = 0;
    // check part 1 is type_1_4 or type_1_2_slide or type_1_2_sw?
    if (gpio_input_bit_get(x_port1, x1_pinse1) == 0 &&
        gpio_input_bit_get(x_port2, x1_pinse2) == 0) {
        if (gpio_input_bit_get(x_port2, x1_pin2) == 0 &&
            gpio_input_bit_get(x_port0, x1_pin3) == 0 &&
            gpio_input_bit_get(x_port2, x1_pin4) == 0) {
            board_all_part.part1 = type_1_2_slide;
            get_key_max += 0;
            // init pa2 adc1 channl 3
            if (is_init == true)
                check_slide_init_adc_dma(board_all_part);
        }
        else if (gpio_input_bit_get(x_port0, x1_pin3) == 0 &&
            gpio_input_bit_get(x_port2, x1_pin4) == 0) {
            board_all_part.part1 = type_1_2_sw;
            get_key_max += 2;
        }
        else {
            board_all_part.part1 = type_1_4;
            get_key_max += 4;
        }
    }
    // check part 1 is type_1_2_y ?
    else if (gpio_input_bit_get(x_port1, x1_pinse1) == 0 &&
        gpio_input_bit_get(x_port2, x1_pinse2) == 1) {
        board_all_part.part1 = type_1_2_y;
        get_key_max += 4;
    }
    // check part 1 is type_1_2_x ?
    else if (gpio_input_bit_get(x_port1, x1_pinse1) == 1 &&
        gpio_input_bit_get(x_port2, x1_pinse2) == 0) {
        board_all_part.part1 = type_1_2_x;
        get_key_max += 4;
    }
    else {
        board_all_part.part1 = type_null;
    }
    // check part 2 is type_1_4 or type_1_2_slide or type_1_2_sw?
    if (gpio_input_bit_get(x_port2, x2_pinse1) == 0 &&
        gpio_input_bit_get(x_port1, x2_pinse2) == 0) {
        if (gpio_input_bit_get(x_port1, x2_pin2) == 0 &&
            gpio_input_bit_get(x_port1, x2_pin3) == 0 &&
            gpio_input_bit_get(x_port1, x2_pin4) == 0) {
            board_all_part.part2 = type_1_2_slide;
            get_key_max += 0;
            // init pa0 adc1 channl 0
            if (is_init == true)
                check_slide_init_adc_dma(board_all_part);
        }
        else if (gpio_input_bit_get(x_port1, x2_pin3) == 0 &&
            gpio_input_bit_get(x_port1, x2_pin4) == 0) {
            board_all_part.part2 = type_1_2_sw;
            get_key_max += 2;
        }
        else {
            board_all_part.part2 = type_1_4;
            get_key_max += 4;
        }
    }
    // check part 2 is type_1_2_y ?
    else if (gpio_input_bit_get(x_port2, x2_pinse1) == 0 &&
        gpio_input_bit_get(x_port1, x2_pinse2) == 1) {
        board_all_part.part2 = type_1_2_y;
        get_key_max += 4;
    }
    // check part 2 is type_1_2_x ?
    else if (gpio_input_bit_get(x_port2, x2_pinse1) == 1 &&
        gpio_input_bit_get(x_port1, x2_pinse2) == 0) {
        board_all_part.part2 = type_1_2_x;
        get_key_max += 4;
    }
    else {
        board_all_part.part2 = type_null;
    }
    // check part 3 is type_1_4 or type_1_2_slide or type_1_2_sw?
    if (gpio_input_bit_get(x_port2, x3_pinse1) == 0 &&
        gpio_input_bit_get(x_port0, x3_pinse2) == 0) {
        if (gpio_input_bit_get(x_port2, x3_pin2) == 0 &&
            gpio_input_bit_get(x_port2, x3_pin3) == 0 &&
            gpio_input_bit_get(x_port2, x3_pin4) == 0) {
            board_all_part.part3 = type_1_2_slide;
            get_key_max += 0;
        }
        else if (gpio_input_bit_get(x_port2, x3_pin3) == 0 &&
            gpio_input_bit_get(x_port2, x3_pin4) == 0) {
            board_all_part.part3 = type_1_2_sw;
            get_key_max += 2;
        }
        else {
            board_all_part.part3 = type_1_4;
            get_key_max += 4;
        }
    }
    // check part 3 is type_1_2_y ?
    else if (gpio_input_bit_get(x_port2, x3_pinse1) == 0 &&
        gpio_input_bit_get(x_port0, x3_pinse2) == 1) {
        board_all_part.part3 = type_1_2_y;
        get_key_max += 4;
    }
    // check part 3 is type_1_2_x ?
    else if (gpio_input_bit_get(x_port2, x3_pinse1) == 1 &&
        gpio_input_bit_get(x_port0, x3_pinse2) == 0) {
        board_all_part.part3 = type_1_2_x;
        get_key_max += 4;
    }
    else {
        board_all_part.part3 = type_null;
    }
    // check part 4 is type_1_4 or type_1_2_slide or type_1_2_sw?
    if (gpio_input_bit_get(x_port1, x4_pinse1) == 0 &&
        gpio_input_bit_get(x_port1, x4_pinse2) == 0) {
        if (gpio_input_bit_get(x_port2, x4_pin2) == 0 &&
            gpio_input_bit_get(x_port2, x4_pin3) == 0 &&
            gpio_input_bit_get(x_port2, x4_pin4) == 0) {
            board_all_part.part4 = type_1_2_slide;
            get_key_max += 0;
        }
        else if (gpio_input_bit_get(x_port2, x4_pin3) == 0 &&
            gpio_input_bit_get(x_port2, x4_pin4) == 0) {
            board_all_part.part4 = type_1_2_sw;
            get_key_max += 2;
        }
        else {
            board_all_part.part4 = type_1_4;
            get_key_max += 4;
        }
    }
    // check part 3 is type_1_2_y ?
    else if (gpio_input_bit_get(x_port1, x4_pinse1) == 0 &&
        gpio_input_bit_get(x_port1, x4_pinse2) == 1) {
        board_all_part.part4 = type_1_2_y;
        get_key_max += 4;
    }
    // check part 3 is type_1_2_x ?
    else if (gpio_input_bit_get(x_port1, x4_pinse1) == 1 &&
        gpio_input_bit_get(x_port1, x4_pinse2) == 0) {
        board_all_part.part4 = type_1_2_x;
        get_key_max += 4;
    }
    else {
        board_all_part.part4 = type_null;
    }
    key.group_num_max = get_key_max;
    key.user_date = &board_all_part;
}
static bool bsp_init(void) {
    rcu_periph_clock_enable(x_rcu0);
    rcu_periph_clock_enable(x_rcu1);
    rcu_periph_clock_enable(x_rcu2);

    gpio_init(x_port0, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ,
        x1_pin1 | x1_pin3 | x1_pin4 | x2_pin1 | x3_pin1 | x3_pinse2 |
        x4_pin1);
    gpio_init(x_port1, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ,
        x1_pinse1 | x2_pin2 | x2_pin3 | x2_pin4 | x2_pinse2 | x4_pinse1 |
        x4_pinse2);
    gpio_init(x_port2, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ,
        x1_pin2 | x1_pinse2 | x2_pinse1 | x3_pin2 | x3_pin3 | x3_pin4 |
        x3_pinse1 | x4_pin2 | x4_pin3 | x4_pin4);
    bsp_check_part(true);
    return true;
}

static void bsp_deinit(void) {
    rcu_periph_clock_enable(x_rcu0);
    rcu_periph_clock_enable(x_rcu1);
    rcu_periph_clock_enable(x_rcu2);

    gpio_init(x_port0, GPIO_MODE_OUT_OD, GPIO_OSPEED_2MHZ,
        x1_pin1 | x1_pin3 | x1_pin4 | x2_pin1 | x3_pin1 | x3_pinse2 |
        x4_pin1);
    gpio_init(x_port1, GPIO_MODE_OUT_OD, GPIO_OSPEED_2MHZ,
        x1_pinse1 | x2_pin2 | x2_pin3 | x2_pin4 | x2_pinse2 | x4_pinse1 |
        x4_pinse2);
    gpio_init(x_port2, GPIO_MODE_OUT_OD, GPIO_OSPEED_2MHZ,
        x1_pin2 | x1_pinse2 | x2_pinse1 | x3_pin2 | x3_pin3 | x3_pin4 |
        x3_pinse1 | x4_pin2 | x4_pin3 | x4_pin4);
}
static unsigned char bsp_get(unsigned char num) {
    if (x1_pin_id1 == num)
        return gpio_input_bit_get(x_port0, x1_pin1);
    else if (x1_pin_id2 == num)
        return gpio_input_bit_get(x_port2, x1_pin2);
    else if (x1_pin_id3 == num)
        return gpio_input_bit_get(x_port0, x1_pin3);
    else if (x1_pin_id4 == num)
        return gpio_input_bit_get(x_port0, x1_pin4);
    else if (x2_pin_id1 == num)
        return gpio_input_bit_get(x_port0, x2_pin1);
    else if (x2_pin_id2 == num)
        return gpio_input_bit_get(x_port1, x2_pin2);
    else if (x2_pin_id3 == num)
        return gpio_input_bit_get(x_port1, x2_pin3);
    else if (x2_pin_id4 == num)
        return gpio_input_bit_get(x_port1, x2_pin4);
    else if (x3_pin_id1 == num)
        return gpio_input_bit_get(x_port0, x3_pin1);
    else if (x3_pin_id2 == num)
        return gpio_input_bit_get(x_port2, x3_pin2);
    else if (x3_pin_id3 == num)
        return gpio_input_bit_get(x_port2, x3_pin3);
    else if (x3_pin_id4 == num)
        return gpio_input_bit_get(x_port2, x3_pin4);
    else if (x4_pin_id1 == num)
        return gpio_input_bit_get(x_port0, x4_pin1);
    else if (x4_pin_id2 == num)
        return gpio_input_bit_get(x_port2, x4_pin2);
    else if (x4_pin_id3 == num)
        return gpio_input_bit_get(x_port2, x4_pin3);
    else if (x4_pin_id4 == num)
        return gpio_input_bit_get(x_port2, x4_pin4);
    return x_pin_id_null;
}
